package com.southgis.ibase.sql.func;

import org.apache.commons.lang3.StringUtils;

import com.southgis.ibase.sql.enums.ColumnTypeEnum;

import lombok.Getter;

/**
 * 为修改表字段准备定义信息，要求先初始化原字段信息后，再调用相应的modifyXXX方法设置修改信息。
 * 如果先有了ColumnDefine对象，按这样的方式生成：
 * <pre>
 * ColumnDefine define={...};
 * ModifyColumnDefine mcd=ModifyColumnDefine.of(define);
 * mcd.modifyName("abc");
 * </pre>
 * @author dennis
 *
 */
public class ModifyColumnDefine extends ColumnDefine
{
	/** 修改字段名时，需要设置原字段名 */
	@Getter
	String oldName;
	
	/** 修改属性掩码 */
	@Getter
	int modifyBit=0;
	
	/** 是否以复制方式修改字段类型（目前在原字段为Lob或修改后的字段为Lob时，要用复制方式修改），
	 * 如果按复制方式修改，在生成修改语句时，会特殊处理（目前只Oracle做特殊处理） */
	@Getter
	boolean byCopyModel=false;
	
	/**
	 * 是否修改名字
	 * @return
	 */
	public boolean isModifyName()
	{
		return (modifyBit&1)==1;
	}
	/**
	 * 是否修改类型
	 * @return
	 */
	public boolean isModifyType()
	{
		return (modifyBit&2)==2;
	}
	/**
	 * 是否修改“可空”约束
	 * @return
	 */
	public boolean isModifyNullable()
	{
		return (modifyBit&4)==4;
	}
	/**
	 * 是否修改注释
	 * @return
	 */
	public boolean isModifyComment()
	{
		return (modifyBit&8)==8;
	}
	
	/**
	 * 重置修改项的状态。【注意】：如果oldName有值（调用了modifyName后），会将oldName还原为name属性值。
	 * @return
	 */
	public ModifyColumnDefine resetModify()
	{
		if(!StringUtils.isEmpty(oldName)) {
			this.setName(oldName);
			oldName=null;
		}
		modifyBit=0;
		byCopyModel=false;
		return this;
	}
	
	/**
	 * 修改字段名。【注意】：如果oldName为空，会先将值设置为name的属性值，因此调用此方法前，确保name属性已设置了正确的原字段名。<br>
	 * 因mysql这样的数据库在修改字段时，也需要提供定义其他信息，因此在不修改某个属性（类型、可空、注释）时，需要设置正确的原信息。
	 * @param name 要改名的字段名
	 * @return
	 */
	public ModifyColumnDefine modifyName(String name)
	{
		if(StringUtils.isEmpty(oldName)) {
			if(StringUtils.isEmpty(this.getName()))
				throw new RuntimeException("修改字段名时，需要先使用setName设置原字段名");
			oldName=this.getName();
		}
		
		this.setName(name); //设置新名字
		modifyBit=modifyBit|1;
		return this;
	}
	
	/**
	 * 修改字段类型。
	 * 因mysql这样的数据库在修改字段时，也需要提供定义其他信息，因此在不修改某个属性（类型、可空、注释）时，需要设置正确的原信息。
	 * @param type
	 * @param length 小于0，表示用lob类型；等于0，表示用默认长度（一般为255），大于0表示确定长度。
	 * @param scale
	 * @param suftype
	 * @return
	 */
	public ModifyColumnDefine modifyType(ColumnTypeEnum type,int length,int scale,String suftype)
	{
		//如果修改的是Lob类型，标识一下，在生成修改语句时，会特殊处理
		if(!byCopyModel) {
			//判断修改的类型是否为“LOB”类型
			if (type == ColumnTypeEnum.Text || type == ColumnTypeEnum.Binary) {
				byCopyModel = length < 0;
			}
			//如果不是，再判断原类型是否为“LOB”类型
			if(!byCopyModel){
				if(this.getType()==ColumnTypeEnum.Text || this.getType()==ColumnTypeEnum.Binary) {
					byCopyModel=this.getLength()<0;
				}
			}
		}
		this.setType(type);
		this.setSuftype(suftype);
		this.setLength(length);
		this.setScale(scale);
		
		modifyBit=modifyBit|2;
		return this;
	}
	/**
	 * 修改是否可空。
	 * 因mysql这样的数据库在修改字段时，也需要提供定义其他信息，因此在不修改某个属性（类型、可空、注释）时，需要设置正确的原信息。
	 * @param nullable
	 * @return
	 */
	public ModifyColumnDefine modifyNullable(boolean nullable)
	{
		this.setNullable(nullable);
		modifyBit=modifyBit|4;
		return this;
	}
	/**
	 * 修改注释。
	 * 因mysql这样的数据库在修改字段时，也需要提供定义其他信息，因此在不修改某个属性（类型、可空、注释）时，需要设置正确的原信息。
	 * @param comment
	 * @return
	 */
	public ModifyColumnDefine modifyComment(String comment)
	{
		this.setComment(comment);
		modifyBit=modifyBit|8;
		return this;
	}
	
	/**
	 * 修改有差异的信息，特别的，如果name属性为空，则表示不修改字段名。
	 * 这里不支持主键的修改（如果需要修改主键，使用sqlOfDropPrimaryKey/sqlOfAddPrimaryKey
	 * @param ref
	 */
	public void modifyDistinct(ColumnDefine ref)
	{
		//this.name = ref.name;
		if(!StringUtils.isEmpty(ref.name) && !ref.name.equalsIgnoreCase(this.name)) {
			this.modifyName(ref.getName());
		}
		//this.comment = ref.comment;
		if(!StringUtils.equals(ref.comment,this.comment)) {
			this.modifyComment(ref.comment);
		}
		//this.type = ref.type;
		//this.suftype = ref.suftype;
		//this.length = ref.length;
		//this.scale = ref.scale;
		//修改字段类型时，不考虑suftype的差异
		if(ref.type!=this.type
				|| this.length != ref.length || this.scale != ref.scale) {
			this.modifyType(ref.type, ref.length, ref.scale, ref.suftype);
		}
		//this.nullable = ref.nullable;
		if(ref.nullable!=this.nullable) {
			this.modifyNullable(ref.nullable);
		}
		//this.primaryKey = ref.primaryKey;
		//主键不支持这样修改
		//if(ref.primaryKey!=this.primaryKey) {
		//	
		//}
	}

	/**
	 * 从定义信息转换成修改信息对象（复制原始信息），后续要调用相应modifyXxx方法进行修改设置
	 * @param define
	 * @return
	 */
	public static ModifyColumnDefine of(ColumnDefine define)
	{
		ModifyColumnDefine mcd=new ModifyColumnDefine();
		mcd.copyFrom(define);
		return mcd;
	}
	

//	public ModifyColumnDefine(){
//
//	}
//	/**
//	 * 单纯修改字段名
//	 * @param newName
//	 * @param oldName
//	 */
//	public ModifyColumnDefine(String newName, String oldName) {
//		this.setName(oldName);
//		this.modifyName(newName);
//	}
//
//	/**
//	 * 修改除了字段名、主键的其他属性情况。
//	 * @param columnDefine
//	 */
//	public ModifyColumnDefine(ColumnDefine columnDefine) {
//		this.setName(columnDefine.getName());
//		this.modifyComment(columnDefine.getComment());
//		this.modifyType(columnDefine.getType(), columnDefine.getLength(), columnDefine.getScale(), columnDefine.getSuftype());
//		this.modifyNullable(columnDefine.isNullable());
//	}
//
//	/**
//	 * 修改除了字段名、主键的其他属性情况。
//	 * @param columnDefine
//	 */
//	public ModifyColumnDefine(ColumnDefine columnDefine, ColumnDefine oldColumnDefine) {
//		this.setName(columnDefine.getName());
//		this.modifyComment(columnDefine.getComment());
//		this.modifyType(columnDefine.getType(), columnDefine.getLength(), columnDefine.getScale(), columnDefine.getSuftype());
//		if(oldColumnDefine.isNullable() != columnDefine.isNullable()){
//			this.modifyNullable(columnDefine.isNullable());
//		}
//	}
}
